<script lang="ts" setup>
import { ref, nextTick, onBeforeMount, watch } from 'vue'
import ReTitle from '@/components/ReTitle/index.vue'
import {
  _queryMenuTreeByRoleId,
  _queryMenuBindOperations,
  _bindRoleAuthMenu,
  _bindRoleAuthOperation,
  _queryMenuBindPermissions,
  _bindRoleAuthPermission
} from '@/api/auth'
import { MenuItem, OperationItem } from '@/api/types'
import { ElTree } from 'element-plus'
import { Message } from '@/utils/message'

const prop = defineProps({
  roleId: Number
})
const menuTree = ref([])
const props = {
  value: 'id',
  children: 'children'
}
const highlightedNode = ref<MenuItem>()
const treeRef = ref<InstanceType<typeof ElTree>>()

onBeforeMount(async () => {
  await search()
})

watch(
  () => highlightedNode.value?.id,
  value => {
    value && queryMenuBindOperations()
    value && queryMenuBindPermissions()
  }
)
let expandedKeys = ref([])
let checkMenuIds = []
/**
 * @description 获取所有一级菜单id
 * @param menuTree 树结构menu
 */
const expandFirstLevelNodes = (menuTree: MenuItem[]) => {
  menuTree.forEach((menu: any) => {
    expandedKeys.value.push(menu.id)
    if (menu.children && menu.children.length > 0) {
      expandFirstLevelNodes(menu.children)
    }
  })
}

/**
 * @description 获取所有 checked 为 true 的节点的 id
 * @param menuTree 树结构menu
 */
const getCheckedMenuIds = (menuTree: MenuItem[]) => {
  menuTree.forEach((menu: MenuItem) => {
    if (menu.checked) {
      checkMenuIds.push(menu.id)
    }
    if (menu.children && menu.children.length > 0) {
      getCheckedMenuIds(menu.children)
    }
  })
}
const search = (): Promise<void> => {
  return _queryMenuTreeByRoleId(prop.roleId).then(res => {
    checkMenuIds = []
    menuTree.value = res.data
    // 展开所有第一级节点
    expandFirstLevelNodes(menuTree.value)
    // treeRef.value.setExpandedKeys(expandedKeys)
    // 获取所有 checked 为 true 的节点的 id
    getCheckedMenuIds(menuTree.value)

    if (menuTree.value.length > 0 && !highlightedNode.value) {
      highlightedNode.value = Object.assign({}, menuTree.value[0])
      nextTick(() => {
        treeRef.value!.setCurrentKey(highlightedNode.value.id)
      })
    }
  })
}

const handleNodeClick = (data: any) => {
  highlightedNode.value = Object.assign({}, data)
}

const clickEdit = () => {
  nextTick(() => {
    treeRef.value.setCheckedKeys(checkMenuIds)
  })
}

const updateRoleMenu = (): Promise<void> => {
  return new Promise((resolve, reject) => {
    const params = {
      roleId: prop.roleId,
      menuIds: treeRef.value
        .getCheckedKeys()
        .concat(treeRef.value.getHalfCheckedKeys())
    }

    _bindRoleAuthMenu(params)
      .then(res => {
        Message.success(res.message)
        search()
        resolve()
      })
      .catch(err => {
        Message.error(err.message)
        reject()
      })
  })
}

/** --------------- transfer oprations ------------*/

const bindOperationCodes = ref<string[]>()
const operationsList = ref<OperationItem[]>()
const bindOperations = ref<OperationItem[]>()
const queryMenuBindOperations = () => {
  _queryMenuBindOperations({
    roleId: prop.roleId,
    menuId: highlightedNode.value.id
  }).then(res => {
    bindOperationCodes.value = res.data.bindOperationCodes
    operationsList.value = res.data.operationList
    bindOperations.value = operationsList.value.filter(item =>
      bindOperationCodes.value.includes(item.code)
    )
  })
}
const filterOptions = (query: string, item: Record<string, any>) =>
  item.name?.includes(query) ||
  item?.code?.includes(query) ||
  item?.permission?.includes(query)

const operationChanged = (value: string[]) => {
  const params = {
    roleId: prop.roleId,
    menuId: highlightedNode.value.id,
    operationCodes: value
  }

  _bindRoleAuthOperation(params)
    .then(res => {
      Message.success(res.message)
    })
    .catch(err => {
      Message.error(err.message)
    })
}

/** --------------- transfer permissions ------------*/
const bindPermissions = ref<string[]>()
const permissionsList = ref<any[]>()
const bindPermissionsList = ref<any[]>()
const queryMenuBindPermissions = () => {
  _queryMenuBindPermissions({
    roleId: prop.roleId,
    menuId: highlightedNode.value.id
  }).then(res => {
    bindPermissions.value = res.data.binds
    permissionsList.value = res.data.list
    bindPermissionsList.value = bindPermissions.value.map(permission => {
      return permissionsList.value.find(item => item.permission === permission)
    })
  })
}

const permissionChanged = (value: string[]) => {
  const params = {
    roleId: prop.roleId,
    menuId: highlightedNode.value.id,
    permissions: value
  }

  _bindRoleAuthPermission(params)
    .then(res => {
      Message.success(res.message)
    })
    .catch(err => {
      Message.error(err.message)
    })
}
</script>

<template>
  <ReTitle
    title="菜单功能权限"
    can-operate
    :submit="updateRoleMenu"
    @edit="clickEdit"
  >
    <template #default="{ status }">
      <div class="flex">
        <div class="menu-tree p-[10px]">
          <el-scrollbar>
            <el-tree
              ref="treeRef"
              style="max-width: 600px"
              :data="menuTree"
              node-key="id"
              :props="props"
              highlight-current
              :show-checkbox="status"
              :default-expanded-keys="expandedKeys"
              :current-node-key="highlightedNode?.id"
              :expand-on-click-node="false"
              @node-click="handleNodeClick"
            >
              <template #default="{ data }">
                <span :class="{ highlight: data.id === highlightedNode?.id }">{{
                  data.zhName
                }}</span>
              </template>
            </el-tree>
          </el-scrollbar>
        </div>

        <div class="menu-operation ml-[20px]">
          <div class="text-sm mb-[20px]">
            所属菜单： {{ highlightedNode?.zhName }}
          </div>
          <el-transfer
            v-if="status"
            v-model="bindOperationCodes"
            filterable
            :filter-method="filterOptions"
            :titles="['可选操作', '已选操作']"
            :props="{
              key: 'code',
              label: 'name'
            }"
            filter-placeholder="筛选操作"
            :data="operationsList"
            @change="operationChanged"
          >
            <template #default="{ option }">
              <div class="flex justify-between">
                <span>{{ option.name }}</span>
                <span>{{ option.code }}</span>
              </div>
            </template>
          </el-transfer>
          <el-table v-else :data="bindOperations">
            <el-table-column label="序号" type="index" width="100" />
            <el-table-column label="操作编码" prop="code" />
            <el-table-column label="操作名称" prop="name" />
          </el-table>

          <el-transfer
            v-if="status"
            v-model="bindPermissions"
            filterable
            :filter-method="filterOptions"
            :titles="['可选接口', '已选接口']"
            :props="{
              key: 'permission',
              label: 'name'
            }"
            filter-placeholder="筛选接口"
            :data="permissionsList"
            @change="permissionChanged"
          >
            <template #default="{ option }">
              <div class="flex justify-between">
                <span>{{ option.name }}</span>
                <span>{{ option.permission }}</span>
              </div>
            </template>
          </el-transfer>
          <el-table v-else :data="bindPermissionsList">
            <el-table-column label="序号" type="index" width="100" />
            <el-table-column label="接口名称" prop="name" />
            <el-table-column label="接口路径" prop="permission" />
          </el-table>
        </div>
      </div>
    </template>
  </ReTitle>
</template>

<style lang="scss" scoped>
:deep(.menu-tree) {
  flex-shrink: 0;
  width: 360px;
  height: 500px;
  border: 1px solid var(--easy-border-color);
  border-radius: var(--easy-border-radius);

  .el-tree-node__content {
    height: 32px;
    font-size: 15px;
    line-height: 32px;
  }
}

.highlight {
  color: var(--el-color-primary); /* 你可以根据需要调整高亮颜色 */
}

.menu-operation {
  flex: 1;
}

:deep(.el-transfer-panel) {
  width: 300px;

  .el-transfer-panel__item {
    width: calc(100% - 40px);
  }

  .el-transfer-panel__body {
    max-height: 500px;
  }
}
</style>
